import mimetypes
import os.path
from dataclasses import dataclass

from flask import current_app
from injector import inject
from langchain_core.pydantic_v1 import BaseModel

from internal.core.tools.categories import BuiltinCategoryManager
from internal.core.tools.providers import ProviderFactory
from internal.exception import NotFoundException


@inject
@dataclass
class ToolsService:
    provider_factory: ProviderFactory
    builtin_categoryManager: BuiltinCategoryManager

    def get_provider_tool(self):
        providers = self.provider_factory.get_providers()
        provider_tools = []
        for provider in providers:
            pro_item = provider.provider_item
            provider_tools_obj = {
                **pro_item.model_dump(),
                "tools": []
            }
            for item in provider.get_tool_all():
                tool = provider.get_tool_fun(item.name)
                tool_obj = {
                    **item.model_dump(),
                    "inputs": self.get_tool_inputs(tool)
                }
                provider_tools_obj["tools"].append(tool_obj)
                provider_tools.append(provider_tools_obj)
        return provider_tools

    def get_tool_provider_find_name(self, provider_name: str, tool_name: str):
        providers = self.provider_factory.get_provider(provider_name)
        if not providers:
            raise NotFoundException("没有该提供商")
        item = providers.provider_item
        tool_bean = providers.get_tool_bean(tool_name)
        tool = providers.get_tool_fun(tool_name)

        provider_tools_obj = {
            "provider": {**item.model_dump()},
            **tool_bean.model_dump(),
            "inputs": self.get_tool_inputs(tool)
        }
        return provider_tools_obj

    def get_provider_icon(self, provier_name: str):
        provider = self.provider_factory.get_provider(provier_name)
        if not provider:
            raise NotFoundException("没有该提供商")
        root_path = os.path.dirname(os.path.dirname(current_app.root_path))
        provider_path = os.path.join(root_path, "internal", "core", "tools", "providers", provier_name)
        icon_path = os.path.join(provider_path, "_asset", provider.provider_item.icon)
        mimetype, _ = mimetypes.guess_type(icon_path)
        mimetype = mimetype or "application/octet-stream"
        with open(icon_path, "rb") as f:
            icon = f.read()
            return icon, mimetype

    @classmethod
    def get_tool_inputs(cls, tool) -> list:
        inputs = []
        if hasattr(tool, "args_schema") and issubclass(tool.args_schema, BaseModel):
            for field_name, model_field in tool.args_schema.__fields__.items():
                inputs.append({
                    "name": field_name,
                    "description": model_field.field_info.description or "",
                    "required": model_field.required,
                    "type": model_field.outer_type_.__name__,
                })
        return inputs

    def get_category(self):
        return [{
            "name": item["bean"].name,
            "category": item["bean"].category,
            "icon": item["icon"]
        } for item in self.builtin_categoryManager.get_category().values()]
